﻿using System;
using System.Linq;

namespace SSTU.Contract.Common
{
	/// <summary>
	/// Class for encapsulating information about errors and necessary flags from facade operations.
	/// </summary>
	public class FacadeResponse
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse"/> class.
		/// </summary>
		/// <param name="dataSource">The data source type.</param>
		public FacadeResponse(FacadeResponseDataSource dataSource)
			: this(dataSource, true, null)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse"/> class.
		/// </summary>
		/// <param name="dataSource">The data source of the response.</param>
		/// <param name="isSuccess">Flag which indicates that operation has completed successfully or no.</param>
		/// <param name="error">The error, value can be null.</param>
		public FacadeResponse(FacadeResponseDataSource dataSource, bool isSuccess, Exception error)
		{
			IsSuccess = isSuccess;
			DataSource = dataSource;
			Error = error;
		}

		/// <summary>
		/// Gets data source of the response.
		/// </summary>
		public FacadeResponseDataSource DataSource { get; private set; }

		/// <summary>
		/// Gets flag which indicates that operation has completed successfully.
		/// </summary>
		public bool IsSuccess { get; private set; }

		/// <summary>
		/// Gets error, if it was thrown in process of operation, or null.
		/// </summary>
		public Exception Error { get; private set; }

		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse&lt;T&gt;"/> class, with successful status,
		/// </summary>
		/// <param name="data">The data of the response.</param>
		/// <param name="dataSource">The data source.</param>
		public static FacadeResponse Completed(FacadeResponseDataSource dataSource)
		{
			var response = new FacadeResponse(dataSource, true, null);
			return response;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse&lt;T&gt;"/> class, with not successful status,
		/// </summary>
		/// <param name="data">The data of the response.</param>
		/// <param name="dataSource">The data source.</param>
		public static FacadeResponse Failed(Exception error, FacadeResponseDataSource dataSource)
		{
			var response = new FacadeResponse(dataSource, false, null);
			return response;
		}
	}

	/// <summary>
	/// Class for encapsulating response data from facades, with information about errors and necessary flags.
	/// </summary>
	/// <typeparam name="T">Type of the data, which returns in response.</typeparam>
	public class FacadeResponse<T> : FacadeResponse
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="data">The data of the response.</param>
		/// <param name="dataSource">The data source of the data and response.</param>
		public FacadeResponse(T data, FacadeResponseDataSource dataSource)
			: this(data, dataSource, true, null)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="data">The data of the response.</param>
		/// <param name="dataSource">The data source of the data and response.</param>
		/// <param name="isSuccess">Flag which indicates that operation has completed successfully or no.</param>
		/// <param name="error">The error, value can be null.</param>
		public FacadeResponse(T data, FacadeResponseDataSource dataSource, bool isSuccess, Exception error)
			: base(dataSource, isSuccess, error)
		{
			Data = data;
		}
		
		/// <summary>
		/// Gets data of the response.
		/// </summary>
		public T Data { get; private set; }

		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse&lt;T&gt;"/> class, with successful status,
		/// </summary>
		/// <param name="data">The data of the response.</param>
		/// <param name="dataSource">The data source.</param>
		public static FacadeResponse<T> Completed<T>(T data, FacadeResponseDataSource dataSource)
		{
			var response = new FacadeResponse<T>(data, dataSource, true, null);
			return response;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="FacadeResponse&lt;T&gt;"/> class, with not successful status,
		/// </summary>
		/// <param name="data">The data of the response.</param>
		/// <param name="dataSource">The data source.</param>
		public static FacadeResponse<T> Failed<T>(Exception error, FacadeResponseDataSource dataSource)
		{
			var response = new FacadeResponse<T>(default(T), dataSource, false, error);
			return response;
		}
	}
}
